<?php
class NCore_Encryption{
	protected static $hashedKey = NULL;
		public function encrypt($value)	{
		// sha256_d converts key to 128 bit result in binary
		$hashedKey = NCore_Encryption::getHashedKey();
			
		// time serves as nonce
		$mt = microtime(true);
		
		// concat base64'd mt and value
		$dataAndMessage = $this->putTogether($mt, $value);
				
		// get mac for data and message
		$mac = $this->hmacSHA256($dataAndMessage, $hashedKey);
		
		$dataAndMessageAndMac = $this->putTogether($dataAndMessage, $mac);
		
		$cipherText = mcrypt_encrypt(MCRYPT_RIJNDAEL_256, $hashedKey, $dataAndMessageAndMac, 'cbc', $this->doubleSHA256($mt));
		
		return $this->putTogether($mt, $cipherText);
	}		public function decrypt($value)	{
		// sha256_d converts key to 128 bit result in binary
		$hashedKey = NCore_Encryption::getHashedKey();
				
		list($mt, $cipherText) = $this->breakApart($value);
				
		$dataAndMessageAndMac = mcrypt_decrypt(MCRYPT_RIJNDAEL_256, $hashedKey, $cipherText, 'cbc', $this->doubleSHA256($mt));
		
		list($dataAndMessage, $mac) = $this->breakApart($dataAndMessageAndMac);
		
		$hmacResult = $this->hmacSHA256($dataAndMessage, $hashedKey);
		
		if($hmacResult != trim($mac))
		{
			throw new Exception('The encrypted value appears to be corrupted.');
		}
		else
		{
			list($mt, $message) = $this->breakApart($dataAndMessage);
			return $message;
		}
	}
	
	protected function getHashedKey()
	{
		if(is_null(NCore_Encryption::$hashedKey))
		{
			// make sure key has been set
			if(is_null($key = N::config('encryption_key')))
				throw new Exception('The encryption_key must be set in the config file.');
			
			NCore_Encryption::$hashedKey = $this->doubleSHA256($key);
		}		
		
		return NCore_Encryption::$hashedKey;
	}
	
	protected function doubleSHA256($value)
	{
		// make sure salt has been set
		if(is_null($salt = N::config('encryption_salt')))
			throw new Exception('The encryption_salt must be set in the config file.');
	
		$value .= $salt;
		return hash('sha256', hash('sha256', $value, true), true);
	}
	
	protected function hmacSHA256($value, $key)
	{
		return hash_hmac('sha256', $value, $key, true);
	}
	
	protected function breakApart($value)
	{
		$elements = explode('|', $value);
		$elements[0] = base64_decode($elements[0]);
		$elements[1] = base64_decode($elements[1]);	
		return $elements;	
	}
	
	protected function putTogether($value1, $value2)
	{
		return base64_encode($value1).'|'.base64_encode($value2);
	}}?>